diff --git a/src/components.d.ts b/src/components.d.ts index 95eed27..391c5a6 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -1,65 +1,65 @@ /* tslint:disable */ /** * This is an autogenerated file created by the Stencil compiler. * It contains typing information for all components that exist in this project. */ import '@stencil/core'; export namespace Components { - interface UcSpinner {} - interface UcSpinnerAttributes extends StencilHTMLAttributes {} + interface WikiDataSpinner {} + interface WikiDataSpinnerAttributes extends StencilHTMLAttributes {} interface WikidataCaptchaJs {} interface WikidataCaptchaJsAttributes extends StencilHTMLAttributes {} } declare global { interface StencilElementInterfaces { - 'UcSpinner': Components.UcSpinner; + 'WikiDataSpinner': Components.WikiDataSpinner; 'WikidataCaptchaJs': Components.WikidataCaptchaJs; } interface StencilIntrinsicElements { - 'uc-spinner': Components.UcSpinnerAttributes; + 'wiki-data-spinner': Components.WikiDataSpinnerAttributes; 'wikidata-captcha-js': Components.WikidataCaptchaJsAttributes; } - interface HTMLUcSpinnerElement extends Components.UcSpinner, HTMLStencilElement {} - var HTMLUcSpinnerElement: { - prototype: HTMLUcSpinnerElement; - new (): HTMLUcSpinnerElement; + interface HTMLWikiDataSpinnerElement extends Components.WikiDataSpinner, HTMLStencilElement {} + var HTMLWikiDataSpinnerElement: { + prototype: HTMLWikiDataSpinnerElement; + new (): HTMLWikiDataSpinnerElement; }; interface HTMLWikidataCaptchaJsElement extends Components.WikidataCaptchaJs, HTMLStencilElement {} var HTMLWikidataCaptchaJsElement: { prototype: HTMLWikidataCaptchaJsElement; new (): HTMLWikidataCaptchaJsElement; }; interface HTMLElementTagNameMap { - 'uc-spinner': HTMLUcSpinnerElement + 'wiki-data-spinner': HTMLWikiDataSpinnerElement 'wikidata-captcha-js': HTMLWikidataCaptchaJsElement } interface ElementTagNameMap { - 'uc-spinner': HTMLUcSpinnerElement; + 'wiki-data-spinner': HTMLWikiDataSpinnerElement; 'wikidata-captcha-js': HTMLWikidataCaptchaJsElement; } export namespace JSX { export interface Element {} export interface IntrinsicElements extends StencilIntrinsicElements { [tagName: string]: any; } } export interface HTMLAttributes extends StencilHTMLAttributes {} } diff --git a/src/components/spinner/spinner.tsx b/src/components/spinner/spinner.tsx index e543b4e..3dd5750 100644 --- a/src/components/spinner/spinner.tsx +++ b/src/components/spinner/spinner.tsx @@ -1,19 +1,19 @@ import { Component } from '@stencil/core'; @Component({ - tag: 'uc-spinner', + tag: 'wiki-data-spinner', styleUrl: './spinner.css', shadow: true }) export class Spinner { render() { return (
); } } diff --git a/src/components/wiki-captcha-js/wiki-api.dto.ts b/src/components/wiki-captcha-js/wiki-api.dto.ts index 94d5f49..e7deaee 100644 --- a/src/components/wiki-captcha-js/wiki-api.dto.ts +++ b/src/components/wiki-captcha-js/wiki-api.dto.ts @@ -1,28 +1,28 @@ export class WikiApiDto { public sessionId: string; public questionList: QuestionDto[]; } export class QuestionDto { public questionText: string; public questionId: string; public questionType: QUESTION_TYPES; public answersAvailable: AnswerDto[]; } export class AnswerDto { public imgUrl: string; public text: string; public userAnswer: UserAnswerDto; } export class UserAnswerDto { public userInput: string; - public selected: boolean; + public selected: boolean = false; } -enum QUESTION_TYPES { +export enum QUESTION_TYPES { IMAGE = 'IMG', FREE_TEXT = 'INPUT', OPTIONS = 'OPTIONS' } diff --git a/src/components/wiki-captcha-js/wiki-captcha-js.css b/src/components/wiki-captcha-js/wiki-captcha-js.css index e69de29..bd89dc4 100644 --- a/src/components/wiki-captcha-js/wiki-captcha-js.css +++ b/src/components/wiki-captcha-js/wiki-captcha-js.css @@ -0,0 +1,100 @@ +:host { + font-family: sans-serif; + border: 2px solid var(--color-primary, black); + margin: 2rem; + padding: 1rem; + display: block; + max-width: 100%; + box-shadow: 0 2px 8px rgba(0,0,0,.26); + border-radius: 3px; + width: 20rem; + overflow: hidden; +} + +.wiki-captcha-box { + font-family: sans-serif; + display: flex; + flex-direction: column; + align-items: center; + max-width: 100%; + padding-left: 1rem; + padding-right: 1rem; +} + +.wiki-captcha-img-container { + display: flex; + flex-wrap: wrap; + width: 15rem; + max-width: 100%; + justify-content: center; + border-radius: 3px; + overflow: hidden; + align-self: center; + border: 2px solid var(--color-primary, black); + box-shadow: 0 2px 8px rgba(0,0,0,.26); +} + +.wiki-captcha-img, +.wiki-captcha-img-selected { + width: 4rem; + height: 6rem; + flex: 1 0 30%; /* 3 images per row */ + cursor: pointer; +} + +.wiki-captcha-img-selected { + outline: 4px solid var(--color-primary-img-highlight, black); + width: 4rem; + height: 6rem; + outline-offset: -4px; +} + +.wiki-captcha-footer { + display: flex; + align-items: center; + padding-top: .5rem; +} + +.wiki-captcha-powered-by { + display: flex; + justify-content: flex-end; + padding-top: .5rem; +} + +.wiki-captcha-powered-by-icon { + max-width: 20%; +} + +.wiki-captcha-submit { +} + +button, +button:focus { + outline: none; +} + +button { + font: inherit; + padding: 0.25rem 0.5rem; + border: 1px solid var(--color-primary, black); + background: var(--color-primary, black); + color: var(--color-primary-inverse, white); + cursor: pointer; +} + +button:hover, +button:active { + background: var(--color-primary-highlight, grey); + border-color: var(--color-primary-highlight, grey); +} + +button:disabled { + background: #ccc; + border-color: #ccc; + color: white; + cursor: not-allowed; +} + +p { + align-self: center; +} diff --git a/src/components/wiki-captcha-js/wiki-captcha-js.tsx b/src/components/wiki-captcha-js/wiki-captcha-js.tsx index 0d7a6f7..fb7a67c 100644 --- a/src/components/wiki-captcha-js/wiki-captcha-js.tsx +++ b/src/components/wiki-captcha-js/wiki-captcha-js.tsx @@ -1,14 +1,125 @@ -import { Component } from '@stencil/core'; +import {Component, State} from '@stencil/core'; +import {AnswerDto, UserAnswerDto, WikiApiDto} from './wiki-api.dto'; @Component({ tag: 'wikidata-captcha-js', styleUrl: './wiki-captcha-js.css', shadow: true }) export class WikiCaptchaJs { + + private readonly WIKI_DATA_URL = 'http://192.168.1.142:8080'; + private readonly WIKI_DATA_ICON = 'https://upload.wikimedia.org/wikipedia/commons/6/66/Wikidata-logo-en.svg'; + private readonly IMAGES_PER_CAPTCHA = 9; + + @State() private questionList: WikiApiDto; + @State() private loading = false; + + componentDidLoad() { + this.fetchQuestions(); + } + render() { - return (
- WikiData Captcha Js + let question = null; + let questionText = null; + let images = null; + let htmlContent = null; + + if (this.questionList && this.questionList.questionList.length > 0) { + question = this.questionList.questionList[0]; + questionText = question.questionText; + + const maxImageSize = question.answersAvailable.length < this.IMAGES_PER_CAPTCHA ? question.answersAvailable.length : this.IMAGES_PER_CAPTCHA; + images = (question.answersAvailable.slice(0, maxImageSize).map(a => + (possible captcha answer + )) + ); + } + + if (this.loading) { + htmlContent = ; + } else { + htmlContent = [ +

{questionText}

, +
+ {images} +
, + ] + } + + return (
+ {htmlContent}
); } + + onImageClick(answer: AnswerDto, event: Event) { + if (!answer.userAnswer) { + answer.userAnswer = new UserAnswerDto(); + answer.userAnswer.selected = false; + } + answer.userAnswer.selected = !answer.userAnswer.selected; + + const imgElem = event.target as HTMLImageElement; + if (answer.userAnswer.selected) { + imgElem.classList.add('wiki-captcha-img-selected'); + } else { + imgElem.classList.remove('wiki-captcha-img-selected'); + } + console.log('event', imgElem); + } + + onSubmitCaptchaAnswers() { + fetch( + this.WIKI_DATA_URL + '/answers', { + method: 'PUT', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify(this.questionList) + } + ) + .then(() => { + this.loading = false; + this.fetchQuestions(); + }) + .catch(err => { + console.log(err); + this.loading = false; + }); + } + + fetchQuestions() { + this.loading = true; + const requestBody = { + 'language': 'en' + }; + fetch( + this.WIKI_DATA_URL + '/questions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify(requestBody) + } + ) + .then(res => res.json()) + .then(parsedRes => { + this.questionList = parsedRes as WikiApiDto; + this.loading = false; + }) + .catch(err => { + console.log(err); + this.loading = false; + }); + } } diff --git a/src/index.html b/src/index.html index fd4c6cb..ad98b37 100644 --- a/src/index.html +++ b/src/index.html @@ -1,23 +1,39 @@ Stencil Component Starter diff --git a/src/test/factory.ts b/src/test/factory.ts new file mode 100644 index 0000000..383c0cf --- /dev/null +++ b/src/test/factory.ts @@ -0,0 +1,36 @@ +import {AnswerDto, QUESTION_TYPES, QuestionDto, WikiApiDto} from '../components/wiki-captcha-js/wiki-api.dto'; + +export class WikiDataFactory { + + public getQuestions(): WikiApiDto { + const questions = new WikiApiDto(); + questions.sessionId = 'abcd'; + questions.questionList = []; + questions.questionList.push(this.getSingleQuestion()); + return questions; + } + + private getSingleQuestion(): QuestionDto { + const question = new QuestionDto(); + question.questionId = '1'; + question.questionText = 'Select ALL images with men'; + question.questionType = QUESTION_TYPES.IMAGE; + question.answersAvailable = []; + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/5/56/Donald_Trump_official_portrait.jpg')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/1/12/Billie_Holiday_0001_original.jpg')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/b/bf/Angela_Merkel._Tallinn_Digital_Summit.jpg')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); + question.answersAvailable.push(this.getAnswer('https://upload.wikimedia.org/wikipedia/commons/f/ff/Human-man.png')); + return question; + } + + private getAnswer(img: string): AnswerDto { + const answer = new AnswerDto(); + answer.imgUrl = img; + return answer; + } +}